package testview.zhen.com.myapplication.design.visitor_design

import android.util.Log
import java.util.*
import java.util.logging.Logger
import kotlin.collections.ArrayList

/**
 * @author :create by ldr
 * time:2022/10/25 11:54
 * @descript:访问者模式
 * 访问者模式的优点。

++++++++++++++++++
访问与被访问都互相引用
++++++++++++++++++
各角色职责分离，符合单一职责原则
通过UML类图和上面的示例可以看出来，Visitor、ConcreteVisitor、Element 、ObjectStructure，职责单一，各司其责。
具有优秀的扩展性
如果需要增加新的访问者，增加实现类 ConcreteVisitor 就可以快速扩展。
使得数据结构和作用于结构上的操作解耦，使得操作集合可以独立变化
员工属性（数据结构）和CEO、CTO访问者（数据操作）的解耦。
灵活性
访问者模式的缺点。

具体元素对访问者公布细节，违反了迪米特原则
CEO、CTO需要调用具体员工的方法。
具体元素变更时导致修改成本大
变更员工属性时，多个访问者都要修改。
违反了依赖倒置原则，为了达到“区别对待”而依赖了具体类，没有以来抽象
访问者 visit 方法中，依赖了具体员工的具体方法。

作者：JamFF
链接：https://www.jianshu.com/p/1f1049d0a0f4
来源：简书
著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
 *
 */
const val VISITOR_TAG = "VISITOR_TAG"
//被访问对象类
abstract class Staff(val name: String, val kpi: Int = Random().nextInt(10)) {
    abstract fun accept(visitor: Visitor)
}

class Engineer(val name1: String) : Staff(name1) {
    val productor = Random().nextInt(100)
    override fun accept(visitor: Visitor) {
        visitor.visit(this)
    }
}

class Manager(val name1: String) : Staff(name1) {
    val productor = Random().nextInt(100)
    override fun accept(visitor: Visitor) {
        visitor.visit(this)
    }
}

//访问类
interface Visitor {
    fun visit(engineer: Engineer)
    fun visit(manager: Manager)
}

//CEO访问类
class CEOVisitor : Visitor {
    override fun visit(engineer: Engineer) {
        System.out.println("${VISITOR_TAG} visit: CEOVisitor -- Engineer ${engineer.name} ${engineer.kpi}")
    }

    override fun visit(manager: Manager) {
        System.out.println("${VISITOR_TAG} visit: CEOVisitor -- Manager ${manager.name} ${manager.kpi}")
    }
}

//CTO访问类
class CTOVisitor : Visitor {
    override fun visit(engineer: Engineer) {
        System.out.println("${VISITOR_TAG} visit: CTOVisitor -- Engineer ${engineer.name} ${engineer.productor}")
    }

    override fun visit(manager: Manager) {
        System.out.println("${VISITOR_TAG} visit: CTOVisitor -- Manager ${manager.name} ${manager.productor}")
    }
}


class BusinessReport {
    val mStaffs = arrayListOf<Staff>()

    constructor() {
        //假设有多个员工
        mStaffs.add(Manager("经理-A"))
        mStaffs.add(Manager("经理-B"))
        mStaffs.add(Engineer("开发-A"))
        mStaffs.add(Manager("开发-B"))
    }

    /**
     * 展示报表
     */
    fun showReport(visitor: Visitor) {
        mStaffs.forEach { staff ->
            staff.accept(visitor)
        }
    }
}

fun main() {
    val businessReport = BusinessReport()
    System.out.println("=============CEO看报表=====================")
    businessReport.showReport(CEOVisitor())
    System.out.println("=============CTO看报表=====================")
    businessReport.showReport(CTOVisitor())
}
